﻿namespace Microsoft.VisualStudio.ServiceModel.DomainServices.Tools
{
    using Microsoft.CSharp;
    using Microsoft.VisualBasic;
    using System;
    using System.CodeDom;
    using System.CodeDom.Compiler;
    using System.Collections.Generic;
    using System.Globalization;
    using System.IO;
    using System.Linq;
    using System.Text;

    internal sealed class CodeGenContext : IDisposable
    {
        private CodeCompileUnit _compileUnit = new CodeCompileUnit();
        private Dictionary<string, CodeNamespace> _namespaces = new Dictionary<string, CodeNamespace>();
        private System.CodeDom.Compiler.CodeGeneratorOptions _options = new System.CodeDom.Compiler.CodeGeneratorOptions();
        private CodeDomProvider _provider;
        private List<string> _references = new List<string>();
        private string _rootNamespace;

        public CodeGenContext(string language, string rootNamespace)
        {
            this._provider = language.Equals("C#") ? ((CodeDomProvider) new CSharpCodeProvider()) : ((CodeDomProvider) new VBCodeProvider());
            this._rootNamespace = rootNamespace;
            this.Initialize();
        }

        internal void AddReference(string reference)
        {
            if (!this._references.Contains<string>(reference, StringComparer.OrdinalIgnoreCase))
            {
                this._references.Add(reference);
            }
        }

        public void Dispose()
        {
            GC.SuppressFinalize(this);
            CodeDomProvider provider = this._provider;
            this._provider = null;
            if (provider != null)
            {
                provider.Dispose();
            }
            this._compileUnit = null;
            this._namespaces = null;
        }

        private void FixUpCompileUnit(CodeCompileUnit compileUnit)
        {
            new DomainServiceFixupCodeDomVisitor(this).Visit(compileUnit);
        }

        private string FixupVBOptionStatements(string code)
        {
            if (this.IsCSharp || (code == null))
            {
                return code;
            }
            StringBuilder builder = new StringBuilder(code);
            string str = "Option Strict Off";
            string newValue = "Option Strict On";
            string str3 = "Option Infer On";
            string str4 = "Option Compare Binary";
            int index = code.IndexOf(str, StringComparison.Ordinal);
            if (index != -1)
            {
                builder.Replace(str, newValue, index, str.Length);
                builder.Insert(index, str3 + Environment.NewLine);
                builder.Insert(index, str4 + Environment.NewLine);
            }
            return builder.ToString();
        }

        internal GeneratedCode GenerateCode()
        {
            string s = string.Empty;
            using (TextWriter writer = new StringWriter(CultureInfo.InvariantCulture))
            {
                this.FixUpCompileUnit(this.CompileUnit);
                this.Provider.GenerateCodeFromCompileUnit(this.CompileUnit, writer, this._options);
                s = this.FixupVBOptionStatements(writer.ToString());
            }
            return new GeneratedCode(CodeGenUtilities.StripAutoGenPrefix(s, this.IsCSharp), this.References);
        }

        internal CodeNamespace GetNamespace(CodeTypeDeclaration typeDecl)
        {
            string key = typeDecl.UserData["Namespace"] as string;
            CodeNamespace namespace2 = null;
            this._namespaces.TryGetValue(key, out namespace2);
            return namespace2;
        }

        private string GetNamespaceName(string namespaceName)
        {
            string str = namespaceName;
            if (!string.IsNullOrEmpty(this._rootNamespace) && namespaceName.Equals(this._rootNamespace, StringComparison.Ordinal))
            {
                return string.Empty;
            }
            if (!string.IsNullOrEmpty(this._rootNamespace) && namespaceName.StartsWith(this._rootNamespace + ".", StringComparison.Ordinal))
            {
                str = namespaceName.Substring(this._rootNamespace.Length + 1);
            }
            return str;
        }

        internal CodeNamespace GetOrGenNamespace(string namespaceName)
        {
            CodeNamespace namespace2 = null;
            if (string.IsNullOrEmpty(namespaceName))
            {
                return null;
            }
            string key = this.GetNamespaceName(namespaceName);
            if (!this._namespaces.TryGetValue(key, out namespace2))
            {
                namespace2 = new CodeNamespace(key);
                this._namespaces[key] = namespace2;
                foreach (string str2 in BusinessLogicClassConstants.FixedImports)
                {
                    CodeNamespaceImport import = new CodeNamespaceImport(str2);
                    namespace2.Imports.Add(import);
                }
                this.CompileUnit.Namespaces.Add(namespace2);
            }
            return namespace2;
        }

        private void Initialize()
        {
            System.CodeDom.Compiler.CodeGeneratorOptions options = new System.CodeDom.Compiler.CodeGeneratorOptions {
                IndentString = "    ",
                VerbatimOrder = true,
                BlankLinesBetweenMembers = true,
                BracingStyle = "C"
            };
            this._options = options;
        }

        internal bool IsValidIdentifier(string identifier)
        {
            return (!string.IsNullOrEmpty(identifier) && this._provider.IsValidIdentifier(identifier));
        }

        internal System.CodeDom.Compiler.CodeGeneratorOptions CodeGeneratorOptions
        {
            get
            {
                return this._options;
            }
        }

        private CodeCompileUnit CompileUnit
        {
            get
            {
                return this._compileUnit;
            }
        }

        internal bool IsCSharp
        {
            get
            {
                return (this._provider is CSharpCodeProvider);
            }
        }

        internal CodeDomProvider Provider
        {
            get
            {
                return this._provider;
            }
        }

        internal IEnumerable<string> References
        {
            get
            {
                return this._references;
            }
        }

        internal string RootNamespace
        {
            get
            {
                return this._rootNamespace;
            }
        }
    }
}

